import hmac
import hashlib
import time
import json

from dotenv import load_dotenv
from fastapi import Request, HTTPException
from typing import Dict, Any, Optional
import os

# 加载环境变量（指定.env文件路径，若文件名非标准）
load_dotenv(dotenv_path="application.env")  # 指定实际的文件名
# 从环境变量获取安全密钥（建议使用至少32字节的随机字符串）
SECRET_KEY = os.environ.get("SECURITY_SECRET_KEY", "").encode()
if not SECRET_KEY:
    raise ValueError("Missing SECURITY_SECRET_KEY environment variable")

# 时间戳验证窗口（秒）
TIMESTAMP_WINDOW = 60 * 10  # 10分钟


class SecurityUtil:
    @staticmethod
    def generate_signature(data: Dict[str, Any], timestamp: int) -> str:
        """生成请求签名"""
        # 1. 对请求数据进行排序（确保参数顺序不影响签名）
        sorted_data = dict(sorted(data.items()))

        # 2. 将数据转换为JSON字符串
        data_str = json.dumps(sorted_data, separators=(',', ':'), ensure_ascii=False)

        # 3. 组合数据和时间戳
        message = f"{data_str}|{timestamp}"

        # 4. 使用HMAC-SHA256生成签名
        signature = hmac.new(
            SECRET_KEY,
            message.encode("utf-8"),
            hashlib.sha256
        ).hexdigest()

        return signature

    @staticmethod
    def verify_signature(signature: str, data: Dict[str, Any], timestamp: int) -> bool:
        """验证签名有效性"""
        # 1. 验证时间戳在有效窗口内
        current_time = int(time.time())
        if abs(current_time - timestamp) > TIMESTAMP_WINDOW:
            return False

        # 2. 计算预期签名
        expected_signature = SecurityUtil.generate_signature(data, timestamp)

        # 3. 使用安全比较防止时序攻击
        return hmac.compare_digest(signature, expected_signature)

    @staticmethod
    async def extract_request_data(request: Request) -> Dict[str, Any]:
        """提取请求中的数据（参数+请求体）"""
        # 1. 获取查询参数
        query_params = dict(request.query_params)

        # 2. 获取请求体（如果有）
        body_data = {}
        if request.method in ["POST", "PUT", "PATCH"]:
            content_type = request.headers.get("content-type", "")
            if "application/json" in content_type:
                try:
                    body_bytes = await request.body()
                    if body_bytes:
                        body_data = json.loads(body_bytes.decode("utf-8"))
                except json.JSONDecodeError:
                    pass
        # 3. 合并查询参数和请求体
        combined_data = {**query_params, **body_data}
        # 4. 移除签名参数（如果存在）
        combined_data.pop("sign", None)
        combined_data.pop("timestamp", None)
        return combined_data
